
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <signal.h>
#include <unistd.h>

#include "base/utils/utils.h"
#include "base/debug/debug_config.h"
#include "base/Svar/Scommand.h"

#include "utils_system.h"

using namespace pi;
using namespace std;

////////////////////////////////////////////////////////////////////////////////
/// run program function
////////////////////////////////////////////////////////////////////////////////

pid_t run_program_(const std::string &cmd)
{
    pid_t pid;

    pid = fork();
    if( pid < 0 ) {
        dbg_pe("Can not create new process! ret = %d\n", pid);
        return -1;
    } else if( 0 == pid ) {
        StringArray sa;

        sa = split_text(cmd, " ");
        if( sa.size() > 0 ) {
            char **arg = NULL;
            int  narg = sa.size();
            int  i;

            if( narg > 0 ) {
                arg = (char**) malloc(sizeof(char*)*(narg+1));
                for(i=0; i<narg; i++) {
                    arg[i] = (char*) malloc(sizeof(char)*(sa[i].size()+16));
                    strcpy(arg[i], sa[i].c_str());
                    printf("argv[%2d] = %s\n", i, arg[i]);
                }
                arg[narg] = NULL;
            }

            execv(sa[0].c_str(), arg);
            dbg_pt("program stopped!");

            if( arg != NULL ) {
                for(i=0; i<narg; i++) {
                    free(arg[i]);
                }
                free(arg);
            }
        }

        exit(0);
    }

    return pid;
}

int stop_program_(pid_t pid)
{
    kill(pid, SIGKILL);
    kill(pid, SIGQUIT);
    kill(pid, SIGTERM);

    return 0;
}

int run_program(const std::string &cmd)
{
    return system(cmd.c_str());
}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

struct RunProgram_InnerData
{
    pid_t   pid;

    RunProgram_InnerData() {
        pid = 0;
    }

    ~RunProgram_InnerData() {
        if( pid > 0 ) stop();
    }

    int run(const std::string &cmd) {
        if( pid > 0 ) stop();

        pid = run_program_(cmd);
        dbg_pt("pid = %d\n", pid);

        return 0;
    }

    int stop(void) {
        if( pid > 0 ) {
            dbg_pt("pid = %d\n", pid);
            stop_program_(pid);
            pid = 0;
        }

        return 0;
    }
};

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

int RunProgram::run(const std::string &cmd, int autoStart)
{
    RunProgram_InnerData *id = (RunProgram_InnerData*) m_data;

    // stop old program
    stop();

    m_cmd = cmd;
    m_autoStart = autoStart;

    if( id != NULL ) {
        id->run(cmd);
    }

    //return start();

    return 0;
}

void RunProgram::stop(void)
{
    RunProgram_InnerData *id = (RunProgram_InnerData*) m_data;

    // stop running program
    if( id != NULL ) {
        id->stop();
    }

    // stop running thread
#if 0
    if( getAlive() ) {
        setAlive(0);
        wait(2);
        kill();
    }
#endif
}

void RunProgram::threadFunc()
{
    while( !shouldStop() ) {
        run_program(m_cmd);

        if( !m_autoStart ) break;
    }
}

int RunProgram::init(void)
{
    RunProgram_InnerData *id = new RunProgram_InnerData;
    m_data = id;

    return 0;
}

int RunProgram::release(void)
{
    stop();

    RunProgram_InnerData *id = (RunProgram_InnerData*) m_data;
    if( id != NULL ) {
        delete id;
        m_data = NULL;
    }

    return 0;
}


////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

void MessageTTS_Scommand_Handle(void *ptr, string command, string sParams)
{
    if( command=="MessageTTS" ) {
        MessageTTS *mTTS = (MessageTTS*) ptr;

        mTTS->pushMessage(sParams);
    }
}


int MessageTTS::run(void)
{
    if( m_isRunning ) return -1;

    // start receving thread
    start();

    m_isRunning = 1;
}

void MessageTTS::stop(void)
{
    if( !m_isRunning ) return;

    // stop thread
    pi::Thread::stop();
    join(10);

    m_isRunning = 0;
}

void MessageTTS::threadFunc()
{
    pi::Rate rate(100);

    // get configures
    std::string     waveFN, msg;
    std::string     cmd;
    int             timeInterval;

    m_cmdESpeak     = svar.GetString("FastGCS.MessageTTS.cmdESpeak", "espeak");
    m_cmdWavPlayer  = svar.GetString("FastGCS.MessageTTS.cmdWavPlayer", "aplay");
    m_soundDev      = svar.GetString("FastGCS.MessageTTS.soundDev", "");
    waveFN          = svar.GetString("FastGCS.MessageTTS.waveFN", "t.wav");
    timeInterval    = svar.GetInt("FastGCS.MessageTTS.timeInterval", 300);

    // loop for ever
    while( !shouldStop() ) {
        if( 0 == popMessage(msg) ) {
            cmd = fmt::sprintf("%s -w '%s' '%s'", m_cmdESpeak, waveFN, msg);
            system(cmd.c_str());

            if( m_soundDev.size() > 0 )
                cmd = fmt::sprintf("%s -D '%s' '%s'", m_cmdWavPlayer, m_soundDev, waveFN);
            else
                cmd = fmt::sprintf("%s '%s'", m_cmdWavPlayer, waveFN);
            system(cmd.c_str());

            tm_sleep(timeInterval);
        }

        rate.sleep();
    }
}

int MessageTTS::init(void)
{
    m_isRunning = 0;

    scommand.RegisterCommand("MessageTTS", MessageTTS_Scommand_Handle, this);

    return 0;
}

int MessageTTS::release(void)
{
    if( m_isRunning ) stop();

    scommand.UnRegisterCommand("MessageTTS");

    return 0;
}
